package sqlproxy

import (
	"database/sql"
	"gitee.com/tziye/renai-go/common"
)

func QueryRows(db *sql.DB, s string, params ...any) *sql.Rows {
	for i := 0; ; i++ {
		rows, err := db.Query(s, params...)
		common.LogErr(err)
		if err == nil {
			return rows
		}
		dealErrAndSleep(i, err)
	}
}

func dealErrAndSleep(i int, err error) {
	if i >= 50 {
		common.PanicErr(err)
	}
	common.SleepMS(100)
}

func QueryRow(db *sql.DB, s string, params ...any) *sql.Row {
	for i := 0; ; i++ {
		row := db.QueryRow(s, params...)
		common.LogErr(row.Err())
		if row.Err() == nil {
			return row
		}
		dealErrAndSleep(i, row.Err())
	}
}

func Exec(db *sql.DB, s string, params ...any) int {
	result := doRetry(db.Exec, s, params...)
	rows, err := result.RowsAffected()
	common.LogErr(err)
	return int(rows)
}

type ExecFunc func(s string, params ...any) (sql.Result, error)

func doRetry(execFunc ExecFunc, s string, params ...any) sql.Result {
	for i := 0; ; i++ {
		result, err := execFunc(s, params...)
		common.LogErr(err)
		if err == nil {
			return result
		}
		dealErrAndSleep(i, err)
	}
}

func BatchExec(db *sql.DB, sqlList []string) {
	for i := 0; ; i++ {
		err := ExecTx(db, sqlList)
		if err == nil {
			return
		}
		dealErrAndSleep(i, err)
	}
}

func ExecTx(db *sql.DB, sqlList []string) error {
	tx, err := db.Begin()
	if err != nil {
		return err
	}
	for _, s := range sqlList {
		_, err1 := tx.Exec(s)
		if err1 != nil {
			err2 := tx.Rollback()
			if err2 != nil {
				common.LogErr(err1)
				return err2
			}
			return err1
		}
	}
	err3 := tx.Commit()
	return err3
}

func CallRows(db *sql.DB, procedure string, params ...any) *sql.Rows {
	s := geneProcedure(procedure, params...)
	return QueryRows(db, s, params...)
}

func CallRow(db *sql.DB, procedure string, params ...any) *sql.Row {
	s := geneProcedure(procedure, params...)
	return QueryRow(db, s, params...)
}

func geneProcedure(procedure string, params ...any) string {
	s := "CALL " + procedure + "("
	for i := 0; i < len(params)-1; i++ {
		s += "?,"
	}
	s += "?)"
	return s
}
